package com.gzh.core.util;

import com.gzh.core.util.constant.ErrorCode;
import com.gzh.core.util.exception.BusinessException;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.model.*;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.utils.IOUtils;
import com.tencent.cloud.CosStsClient;
import com.tencent.cloud.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.List;
import java.util.TreeMap;

@Slf4j
public class CosUtils {

  private static String secretId = "AKID3vXswkHYYImytWt2vXtymJZZLr65nEOI";

  private static String secretKey = "e29zZtwiFWWHn20g5E7k5B0Zrte8MJzP";

  private static String region = "ap-shanghai";

  private static String appid = "1307568725";


  public static String sessionToken = null;

  public static Response getTemporaryKey() {
    try {
      TreeMap<String, Object> config = new TreeMap<>();
      //密钥
      config.put("SecretId", secretId);
      config.put("SecretKey", secretKey);
      //临时密钥有效时间
      config.put("durationSeconds", 1800);
      //bucket
      config.put("bucket", "picture-1307568725");
      // 换成 bucket 所在地区
      config.put("region", region);
      //允许访问的权限
      config.put("allowPrefix", "*");
      // 密钥的权限列表。必须在这里指定本次临时密钥所需要的权限。
      String[] allowActions = new String[]{
        // 简单上传
        "name/cos:PutObject",
        // 表单上传、小程序上传
        "name/cos:PostObject",
        // 分片上传
        "name/cos:InitiateMultipartUpload",
        "name/cos:ListMultipartUploads",
        "name/cos:ListParts",
        "name/cos:UploadPart",
        "name/cos:CompleteMultipartUpload"
      };
      config.put("allowActions", allowActions);
      Response credential = CosStsClient.getCredential(config);
      return credential;
    } catch (IOException e) {
      //失败抛出异常
      throw new IllegalArgumentException("no valid secret !");
    }
  }

  /**
   * 临时密钥
   *
   * @return
   */
  public static COSClient getTempCOSClient() {
    Response response = getTemporaryKey();
    String tmpSecretId = response.credentials.tmpSecretId;
    String tmpSecretKey = response.credentials.tmpSecretKey;
    sessionToken = response.credentials.sessionToken;
    // 1 初始化用户身份信息
    COSCredentials cred = new BasicCOSCredentials(tmpSecretId, tmpSecretKey);
    // 2 设置 bucket 区域
    ClientConfig clientConfig = new ClientConfig(new Region(region));
    // 3 生成 cos 客户端
    COSClient cosClient = new COSClient(cred, clientConfig);
    return cosClient;
  }

  public static COSClient getCOSClient() {
    // 1 初始化用户身份信息
    COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
    // 2 设置 bucket 区域
    ClientConfig clientConfig = new ClientConfig(new Region(region));
    // 3 生成 cos 客户端
    COSClient cosClient = new COSClient(cred, clientConfig);
    return cosClient;
  }

  public static String upload(MultipartFile multipartFile,String bucketName , String prePath) {
    if (multipartFile.isEmpty()) {
      return null;
    }
    COSClient cosClient = getCOSClient();
    String fileName = multipartFile.getOriginalFilename();
    String path = prePath + "/" + fileName;
    InputStream inputStream = null;
    try {
      inputStream = multipartFile.getInputStream();
    } catch (IOException e) {
      e.printStackTrace();
      throw new BusinessException(ErrorCode.UPLOAD_110);
    }
    // sessionToken
    ObjectMetadata objectMetadata = new ObjectMetadata();
//    objectMetadata.setSecurityToken(sessionToken);
    // 设置输入流长度
    objectMetadata.setContentLength(multipartFile.getSize());
    // 流类型上传,需要事先设置输入流长度，不然报错
    PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, path, inputStream, objectMetadata);
    String etag = "";
    try {
      PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
      // 成功：putobjectResult 会返回文件的 etag
      etag = putObjectResult.getETag();
    } catch (Exception e) {
      log.error("文件上传cos失败", e);
      throw new BusinessException(ErrorCode.UPLOAD_110);
    } finally {
      if (inputStream != null) {
        try {
          inputStream.close();
        } catch (IOException e) {
          log.error("输入流关闭失败", e);
          throw new BusinessException(ErrorCode.UPLOAD_110);
        }
      }
      // 关闭客户端
      cosClient.shutdown();
    }
    return path;
  }


  public static String upload(byte[] result,String bucketName , String prePath) {
    COSClient cosClient = getCOSClient();
    InputStream inputStream = null;
    String uuid=StringUtils.getUUID();//uuid作为保存时的文件名
    String fileName = uuid + ".png";//3,字节流转文件
    String path = prePath + "/" + fileName;
    try {
      inputStream = new ByteArrayInputStream(result);
      // sessionToken
      ObjectMetadata objectMetadata = new ObjectMetadata();
//    objectMetadata.setSecurityToken(sessionToken);
      // 设置输入流长度
      objectMetadata.setContentLength(inputStream.available());
      // 流类型上传,需要事先设置输入流长度，不然报错
      PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, path, inputStream, objectMetadata);
      String etag = "";
      PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
      // 成功：putobjectResult 会返回文件的 etag
      etag = putObjectResult.getETag();
    } catch (Exception e) {
      log.error("文件上传cos失败", e);
      throw new BusinessException(ErrorCode.UPLOAD_110);
    } finally {
      if (inputStream != null) {
        try {
          inputStream.close();
        } catch (IOException e) {
          log.error("输入流关闭失败", e);
          throw new BusinessException(ErrorCode.UPLOAD_110);
        }
      }
      // 关闭客户端
      cosClient.shutdown();
    }
    return path;
  }

  public static void downLoad(String bucketName, String key, String fileName, HttpServletResponse response) {
    COSClient cosClient = getCOSClient();
    GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
    // 限流使用的单位是 bit/s, 这里设置下载带宽限制为10MB/s
    getObjectRequest.setTrafficLimit(80 * 1024 * 1024);
    COSObject cosObject = cosClient.getObject(getObjectRequest);
    COSObjectInputStream cosObjectInput = cosObject.getObjectContent();
    OutputStream os = null;
    byte[] bytes = null;
    try {
      //指明为下载
      response.setContentType("application/octet-stream");
      response.addHeader("Content-disposition", "attachment; filename=" + java.net.URLEncoder.encode(fileName, "utf-8"));
      os = response.getOutputStream();
      bytes = IOUtils.toByteArray(cosObjectInput);
      os.write(bytes);
      os.flush();
    } catch (IOException e) {
      log.error("文件下载失败", e);
    } finally {
      if (cosObjectInput != null) {
        try {
          cosObjectInput.close();
        } catch (IOException e) {
          log.error("cosObjectInput关闭失败", e);
        }
      }
      if (os != null) {
        try {
          os.close();
        } catch (IOException e) {
          log.error("输出流关闭失败", e);
        }
        cosClient.shutdown();
      }
    }

  }

  public static void delete(String bucketName, String key) {
    COSClient cosClient = null;
    try {
      cosClient = getCOSClient();
      cosClient.deleteObject(bucketName, key);
    } catch (Exception e) {
      log.error("删除文件失败", e);
    } finally {
      if (cosClient != null) {
        cosClient.shutdown();
      }
    }
  }

  public List<Bucket> listBuckets() {
    COSClient cosClient = getCOSClient();
    List<Bucket> buckets = cosClient.listBuckets();
    return buckets;
  }


  public Bucket createBucket(String  bucketName){
    COSClient cosClient = getCOSClient();
    String bucket = bucketName + appid ; //存储桶名称，格式：BucketName-APPID
    CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucket);
    // 设置 bucket 的权限为 Private(私有读写), 其他可选有公有读私有写, 公有读写
    createBucketRequest.setCannedAcl(CannedAccessControlList.Private);
    Bucket bucketResult = cosClient.createBucket(createBucketRequest);
    return bucketResult;
  }

  public static String getImg(String bucketName,String key) {
    COSClient cosClient = getCOSClient();
      // 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
    // 对象键(Key)是对象在存储桶中的唯一标识。详情请参见 [对象键](https://cloud.tencent.com/document/product/436/13324)
    URL objectUrl = cosClient.getObjectUrl(bucketName, key);
    return objectUrl.toString();
  }
}
